# -*- coding: utf-8 -*-
import paho.mqtt.client as mqtt
import json
from KitUtil import KitUtil


class MQTTConnector:

    TASK_TOPIC_VCTL = "vctlTopic"
    TASK_TOPIC_CARLA = "carlaTopic"

    CLIENT_ID_VCTL = "vctlConnector"
    CLIENT_ID_CARLA = "carlaConnector"

    def __init__(self, clientId, subTpc, pubTpc, useTLS=False, verifyBrokerHost=False, msg_cb=print, echoFun=print):
        self.clientId = clientId
        self.subTpc = subTpc
        self.pubTpc = pubTpc
        self.useTLS = useTLS
        self.msg_cb = msg_cb
        self.echoFun = echoFun
        self.start_cb = None
        self.stop_cb = None

        self.brokerHost = "127.0.0.1"
        self.brokerPort = 1883

        self.client = mqtt.Client(self.clientId)
        self.client.on_connect = self.on_connect
        self.client.on_disconnect = self.on_disconnect
        self.client.on_message = self.on_message
        if useTLS:
            self.client.tls_set(ca_certs="tls/ca_certs.pem", certfile="tls/certfile.pem", keyfile="tls/keyfile.pem")
            if not verifyBrokerHost:
                self.client.tls_insecure_set(True)

    def on_connect(self, client, userdata, flags, rc):
        echoInfo = f"{self.clientId} connect {self.brokerHost}:{self.brokerPort} ok,rc={mqtt.connack_string(rc)}"
        # Carla服务连接器，订阅车辆控制器消息
        client.subscribe(self.subTpc)
        if self.echoFun:
            self.echoFun(echoInfo)
            self.echoFun(f"subscribe {self.subTpc} over.")
        if self.start_cb:
            self.start_cb()
# C:\carla\PythonAPI\examples
    def on_disconnect(self, client, userdata, rc):
        if rc != 0:
            self.echoFun("Unexpected disconnection.")
            self.echoFun(mqtt.connack_string(rc))
        # self.echoFun(f"{self.clientId} disconnected.")
        if self.stop_cb:
            self.stop_cb()

    def on_message(self, client, userdata, msg):
        # print(f"msg.payload type:{type(msg.payload)}")
        # 将payload(二进制)在底层转换为字典,便于上层使用
        pldDict = json.loads(msg.payload)
        # print(f"pldDict type:{type(pldDict)}")
        # echo_info = f"{self.clientId} rcv topic:{msg.topic}  {pldDict}"
        # print(echo_info)
        if self.msg_cb:
            # 以Dict方式返回，方便业务层处理
            self.msg_cb(pldDict, userdata)

    def sendMsg(self, msg):
        """
        内部会将msg当做值，放在固定的字典结构(JSON)里，然后将字典转换成字符串发出去
        :param msg: 要发送的消息内容
        :return:
        """
        payload = {"info": msg, "time": f"{KitUtil.getCrtTime()}"}
        self.client.publish(self.pubTpc, json.dumps(payload, ensure_ascii=False))
        if self.echoFun:
            self.echoFun(f"msg <{msg}> send over.")

    def sendMsgJsonStr(self, jsonStr):
        """
        将给定的JSON字符串直接发出去
        :param jsonStr: JSON字符串
        :return:
        """
        # 直接发送jsonStr
        self.client.publish(self.pubTpc, jsonStr)
        if self.echoFun:
            self.echoFun(f"msg <{jsonStr}> send over.")

    def sendMsgDict(self, dictObj):
        """
        将给定的Dict对象发送出去
        :param dictObj:
        :return:
        """
        # 需要将字典转换为字符串后发送
        strData = json.dumps(dictObj, ensure_ascii=False)
        self.client.publish(self.pubTpc, strData)
        if self.echoFun:
            self.echoFun(f"msg <{dictObj}> send over.")

    def startConnector(self, brokerHost, brokerPort, start_cb=None):
        self.brokerHost = brokerHost
        self.brokerPort = brokerPort
        self.start_cb = start_cb
        try:
            self.client.connect(self.brokerHost, self.brokerPort, 60)
        except Exception as connErr:
            self.echoFun(connErr)
            return
        self.echoFun(f"{self.clientId} loop get message now.")
        # 这个loop_forever()调用会阻塞，直道连接被断开才结束。
        self.client.loop_forever()
        self.echoFun("connect closed,loop get message stopped.")

    def stopConnector(self, stop_cb=None):
        self.stop_cb = stop_cb
        if self.client and self.client.is_connected():
            self.client.unsubscribe(self.subTpc)
            self.echoFun(f"unsubscribe {self.subTpc} over.")
            self.client.disconnect()





